package cn.virens.support;

import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.function.Consumer;

import org.tio.core.ChannelContext;
import org.tio.core.Tio;
import org.tio.utils.lock.SetWithLock;

import cn.virens.App;
import cn.virens.TCPServerDevice;
import cn.virens.TioUtil;
import cn.virens.app.common.BytesBuilder;
import cn.virens.app.common.SQL;
import cn.virens.common.ByteUtil;
import cn.virens.exception.ReconnectException;
import cn.virens.exception.TimeoutException;
import cn.virens.packet.WritePacket;

public class TCPServerImplDevice extends TCPServerImpl implements TCPServerDevice {

	@Override
	public ChannelContext channelGet(String mac) {
		return Tio.getChannelContextByBsId(serverGroupContext, mac);
	}

	@Override
	public void channelbind(ChannelContext channelContext, String mac) {
		Tio.bindBsId(channelContext, mac);
	}

	@Override
	public void channelbindVer(ChannelContext channelContext, String ver) {
		channelContext.setAttribute("ver", ver);
	}

	@Override
	public void channelUnbind(ChannelContext channelContext) {
		Tio.unbindBsId(channelContext);
	}

	@Override
	public void channelForEach(Consumer<ChannelContext> consumer) {
		SetWithLock<ChannelContext> setWithLock = this.serverGroupContext.connections;
		ReadLock readLock = setWithLock.readLock();

		readLock.lock();
		try {
			for (ChannelContext channelContext : setWithLock.getObj()) {
				consumer.accept(channelContext);
			}
		} catch (Throwable e) {
			logger.error(e.getMessage(), e);
		} finally {
			readLock.unlock();
		}
	}

	@Override
	public void channelTimeout(ChannelContext channelContext, Integer idleCount, Integer heartbeat) {
		Tio.remove(channelContext, TimeoutException.of(idleCount, heartbeat), "连接超时");
	}

	@Override
	public void channelReconnect(ChannelContext oldChannelContext, ChannelContext channelContext) {
		Tio.remove(oldChannelContext, ReconnectException.of(channelContext), "连接重连");
	}

	/**
	 * 开关设备指令
	 */
	@Override
	public String deviceSwitch(String imei, String type, String acStatus, String deviceStatus) {
		ChannelContext channelContext = channelGet(imei);
		if (channelContext == null) return "DEVICE_NOT_FIND";

		// 构建发送指令包
		// 构建待发送数据
		BytesBuilder builder = new BytesBuilder();
		builder.append(type, 1);//租赁模式
		builder.append(acStatus, 1);//激活状态
		builder.append(deviceStatus, 1);//水机状态

		// 构建指令包
		WritePacket writePacket = TioUtil.write(channelContext);
		writePacket.data(builder.toArray());
		writePacket.cmd("0003");

		//执行插入操作（插入指令到数据库中，用于收到应答包之后的处理,data去了包头和包尾）
		App.db().executeUpdate(SQL.INSTRUCTION_IN, writePacket.seq(), imei, ByteUtil.toHex((writePacket.data())));

		// 执行发送
		if (TioUtil.write(channelContext, writePacket)) return "SUCCESS------>设备：" + imei + "开关指令发送成功";
		return "FALSE------>设备：" + imei + "开关指令发送失败";
	}

	@Override
	public String activation(String imei, byte[] bs) {
		ChannelContext channelContext = channelGet(imei);
		if (channelContext == null) return "DEVICE_NOT_FIND";

		// 构建指令包
		WritePacket writePacket = TioUtil.write(channelContext);
		writePacket.data(bs);
		writePacket.cmd("0003");

		//执行插入操作（插入指令到数据库中，用于收到应答包之后的处理,data去了包头和包尾）
		App.db().executeUpdate(SQL.INSTRUCTION_IN, writePacket.seq(), imei, ByteUtil.toHex((writePacket.data())));

		// 执行发送
		if (TioUtil.write(channelContext, writePacket)) return "设备：" + imei + "激活指令发送成功";
		return "设备：" + imei + "激活指令发送失败";
	}

	@Override
	public String queryData(String imei) {
		ChannelContext channelContext = channelGet(imei);
		// 构建指令包
		WritePacket writePacket = TioUtil.write(channelContext);
		writePacket.cmd("0002");

		// 执行发送
		if (TioUtil.write(channelContext, writePacket)) {
			logger.debug("手动下发--------->查询数据0002指令已下发");
		}
		return "设备" + imei + "查询数据指令已下发";
	}
}
